import sys
import traceback


def getDataByKey(listData, key, code):
    for item in listData:
        if item[code] == key:
            return item['VALUE']
    return None


F_INDEX_KEYS = ["activity15", "debtcoverage10", "debtcoverage12", "growth2", "leverage3", "profitability16"]

#
Deficiency_Keys = ["HY008",
                   "HY006",
                   "HY035",
                   "HY034",
                   "HY038",
                   "HY017"]


# 计算利息保障倍数
def lixibaozhangbeishu(reportT0, annualData):
    try:
        zx_tot_profit = getNumber(reportT0, "zx_tot_profit")
        zx_fin_exp_is = getNumber(reportT0, "zx_fin_exp_is")
        zx_detailed_fin_int_exp_T0 = getSubject(annualData, "HG0004")
        zx_detailed_fin_int_inc_T0 = getSubject(annualData, "HG0005")
        # 费用化利息支出+资本化利息支出小于等于0，则利息保障倍数指标缺失
        if zx_detailed_fin_int_exp_T0 - zx_detailed_fin_int_inc_T0 <= 0:
            return None
        data1 = zx_tot_profit + zx_fin_exp_is
        data2 = zx_detailed_fin_int_exp_T0 - zx_detailed_fin_int_inc_T0
        return data1 / data2
    except Exception as e:
        return None


def verifyModelResult(param, oIndexKeys, industry):
    if param.__contains__("f_indx") == False or param.__contains__("o_indx") == False:
        return False
    emptyCnt = 0

    # 检查财务指标
    fIndex = param["f_indx"]
    for s in F_INDEX_KEYS:
        if fIndex.__contains__(s) and fIndex[s].__contains__("is_nan") and not isEmpty(fIndex[s]["is_nan"]):
            emptyCnt = emptyCnt + 1
    if emptyCnt >= 2:
        return False
    # 检查非财务指标
    emptyCnt = 0
    oIndex = param["o_indx"]
    for s in oIndexKeys:
        if oIndex.__contains__(s) and oIndex[s].__contains__("is_nan") and not isEmpty(oIndex[s]["is_nan"]):
            emptyCnt = emptyCnt + 1

    # 缺失4个以上指标产业判断
    if industry == 'HY015':
        return False if emptyCnt >= 4 else True
    # 缺失3个以上指标产业判断
    for s in Deficiency_Keys:
        if industry == s:
            return False if emptyCnt >= 3 else True
    if emptyCnt >= 2:
        return False

    return True


def genAdjustmentData(num):
    ad = {
        "num": num,
        "enabled": 0 if num == 0 else 1
    }
    return ad


# 从对象中取值，如果没有返回空字符串
def getDataByKeyIsNull(map, key):
    if map.__contains__(key) and map[key] is not None:
        return map[key]
    return ""


# 从对象中取值，如果没有返回指定字符
def getDataByKeyIsAssign(map, key, assign):
    if map.__contains__(key) and map[key] is not None:
        return map[key]
    return assign


# 取值再除以指定数值
def getDataByKeyIsNullDivide(map, key, num):
    try:
        if map.__contains__(key) == False:
            return ""
        if map[key] is None:
            return ""
        return float(map[key]) / float(num)
    except Exception as e:
        print("取值异常" + key)
        return ""


# 所有数值相加
def allSum(*tupleArg):
    return sum(x for x in tupleArg if x is not None)


# 生成空得subValue结构体
def genItemEmpty(*tupleArg):
    subValue = {}
    for item in tupleArg:
        subValue[item] = ""
    ret = {
        "sum_value": "",
        "sub_value": subValue
    }
    return ret


def setSumValue(value):
    ret = {
        "sum_value": value,
        "sub_value": {}
    }
    return ret


def setSumValueByObj(obj, key):
    value = ""
    if type(obj) == 'object' and len(obj) != 0:
        value = ""
    else:
        if obj.__contains__(key):
            value = obj[key]
    ret = {
        "sum_value": value,
        "sub_value": {}
    }
    return ret


def xianjinxunhuanzhouqiAverage(reportT0, reportT1, reportT2, reportT3):
    # T0现金循环周期
    zqT0 = xjxhzqQe(reportT0, reportT1)
    # T1现金循环周期
    zqT1 = xjxhzqQe(reportT1, reportT2)
    # T2现金循环周期
    zqT2 = xjxhzqQe(reportT2, reportT3)
    mean = calculate_arithmetic_mean([zqT0, zqT1, zqT2])
    sum_value = mean
    if mean is None:
        sum_value = ''
    ret = {
        "sub_value": {
            "chengben_t0": "",
            "cunhuo_t0": "",
            "cunhuo_t1": "",
            "shouru_t0": "",
            "yingshou_t0": "",
            "yingshou_t1": "",
            "yingfu_t0": "",
            "yingfu_t1": "",
        },
        "sum_value": sum_value
    }

    return ret


# 计算算数平均数
def calculate_arithmetic_mean(numbers: list):
    """
    计算给定数字列表的算术平均数。

    参数：
    numbers (list): 包含数字的列表。

    返回：
    float: 算术平均数。
    """
    try:
        numbers = list(filter(None, numbers))
        if not numbers:
            return None
        numbers = list(map(float, numbers))
        total = sum(numbers)
        mean = total / len(numbers)
        return mean
    except Exception as e:
        traceback.print_exc()
        return None


def xjxhzqQe(reportT0, reportT1):
    zx_inventoriesT0 = getSubject(reportT0, "zx_inventories")
    zx_inventoriesT1 = getSubject(reportT1, "zx_inventories")
    zx_acctandnotes_rcvT0 = getSubject(reportT0, "zx_acctandnotes_rcv")
    zx_acctandnotes_rcvT1 = getSubject(reportT1, "zx_acctandnotes_rcv")
    zx_acctandnotes_payableT0 = getSubject(reportT0, "zx_acctandnotes_payable")
    zx_acctandnotes_payableT1 = getSubject(reportT1, "zx_acctandnotes_payable")
    zx_oper_rev = getSubject(reportT0, "zx_oper_rev")
    zx_oper_cost = getSubject(reportT0, "zx_oper_cost")
    if zx_inventoriesT0 == 0 or zx_inventoriesT1 == 0 or zx_acctandnotes_rcvT0 == 0 or zx_acctandnotes_rcvT1 == 0 or zx_acctandnotes_payableT0 == 0 \
            or zx_acctandnotes_payableT1 == 0 or zx_oper_rev == 0 or zx_oper_cost == 0:
        return None
    else:
        days = 360
        # 存货周转天数
        zx_inventories = zx_inventoriesT0 + zx_inventoriesT1
        data1 = zx_oper_cost / zx_inventories * 2
        chzzts = 0 if data1 == 0 else days / data1
        # 应收账款周转天数
        zx_acctandnotes_rcv = zx_acctandnotes_rcvT0 + zx_acctandnotes_rcvT1
        data2 = zx_oper_rev / zx_acctandnotes_rcv * 2
        yszkzzts = 0 if data2 == 0 else days / data2
        zx_acctandnotes_payable = zx_acctandnotes_payableT0 + zx_acctandnotes_payableT1
        data3 = zx_oper_cost / zx_acctandnotes_payable * 2
        yfzkzzts = 0 if data3 == 0 else days / data3
        # 现金循环周期
        return chzzts + yszkzzts - yfzkzzts


# 计算现金循环周期
def xjxhzq(reportT0, reportT1):
    zx_inventoriesT0 = getSubject(reportT0, "zx_inventories")
    zx_inventoriesT1 = getSubject(reportT1, "zx_inventories")
    zx_acctandnotes_rcvT0 = getSubject(reportT0, "zx_acctandnotes_rcv")
    zx_acctandnotes_rcvT1 = getSubject(reportT1, "zx_acctandnotes_rcv")
    zx_acctandnotes_payableT0 = getSubject(reportT0, "zx_acctandnotes_payable")
    zx_acctandnotes_payableT1 = getSubject(reportT1, "zx_acctandnotes_payable")
    zx_oper_rev = getSubject(reportT0, "zx_oper_rev")
    zx_oper_cost = getSubject(reportT0, "zx_oper_cost")
    if zx_inventoriesT0 == 0 or zx_inventoriesT1 == 0 or zx_acctandnotes_rcvT0 == 0 or zx_acctandnotes_rcvT1 == 0 or zx_acctandnotes_payableT0 == 0 \
            or zx_acctandnotes_payableT1 == 0 or zx_oper_rev == 0 or zx_oper_cost == 0:
        ret = {
            "sub_value": {
                "chengben_t0": "",
                "cunhuo_t0": "",
                "cunhuo_t1": "",
                "shouru_t0": "",
                "yingshou_t0": "",
                "yingshou_t1": "",
                "yingfu_t0": "",
                "yingfu_t1": "",
            },
            "sum_value": ""
        }
        return ret
    else:
        days = 360
        # 存货周转天数
        zx_inventories = zx_inventoriesT0 + zx_inventoriesT1
        data1 = zx_oper_cost / zx_inventories * 2
        chzzts = 0 if data1 == 0 else days / data1
        # 应收账款周转天数
        zx_acctandnotes_rcv = zx_acctandnotes_rcvT0 + zx_acctandnotes_rcvT1
        data2 = zx_oper_rev / zx_acctandnotes_rcv * 2
        yszkzzts = 0 if data2 == 0 else days / data2
        zx_acctandnotes_payable = zx_acctandnotes_payableT0 + zx_acctandnotes_payableT1
        data3 = zx_oper_cost / zx_acctandnotes_payable * 2
        yfzkzzts = 0 if data3 == 0 else days / data3
        # 现金循环周期
        ret = {
            "sub_value": {},
            "sum_value": chzzts + yszkzzts - yfzkzzts
        }
        return ret


# 取值再乘指定数值
def getDataByKeyIsNullMultiply(map, key, num):
    if map.__contains__(key) == False:
        return ""
    if map[key] is None:
        return ""
    return float(map[key]) * num


# 判断是否为空，为空返回True 不为空返回False
def isEmptyKv(obj, key):
    if obj is None:
        return True
    if type(obj) == 'object' or isinstance(obj, dict):
        if obj.__contains__(key) and obj[key] is not None and len(obj[key]) != 0:
            return False
    return True


def isEmpty(obj):
    if obj is None or obj == '':
        return True
    return False


def isNone(str):
    if str is None:
        return ''
    return str


# 从对象中拿出数值型，如果没有 返回None
def getNumber(obj, key):
    if obj is None:
        return None
    if isinstance(obj, dict):
        if obj.__contains__(key) and obj[key] is not None and len(obj[key]) != 0:
            return float(obj[key])
    return None


# 数值为空，当0处理
def isNoneToZero(num):
    if num is None:
        return 0
    return num


# 从对象中取值，为空会返回0.00
def getSubject(reportData, key):
    try:
        if reportData.__contains__(key):
            return float(reportData[key])
        return 0.00
    except Exception as e:
        return 0.00


def getValueByKey(reportData, key):
    if reportData.__contains__(key):
        return reportData[key]
    return 0.00


# 计算短期有息债务
def getDqyxzw(reportData):
    return getSubject(reportData, "zx_st_borrow") + getSubject(reportData, "zx_tradable_fin_liab") + getSubject(
        reportData, "zx_notes_payable") + getSubject(reportData, "zx_non_cur_liab_due_within_1y") + getSubject(
        reportData, "zx_st_bonds_payable")


def getDqyxzwT0(reportData):
    # 短期借款T0+以公允价值计量且其变动计入档期损益的金融负债T0+应付票据T0+一年内到期的非流动负债T0+应付短期债券T0
    ret = {
        "dqjk_t0": getSubject(reportData, "zx_st_borrow"),
        "jrfz_t0": getSubject(reportData, "zx_tradable_fin_liab"),
        "yfpj_t0": getSubject(reportData, "zx_notes_payable"),
        "fldfz_t0": getSubject(reportData, "zx_non_cur_liab_due_within_1y"),
        "yfdz_t0": getSubject(reportData, "zx_st_bonds_payable")
    }
    return ret;


# 计算有息债务
def getYxzw(reportData):
    try:
        return getSubject(reportData, "zx_st_borrow") + getSubject(reportData, "zx_tradable_fin_liab") + getSubject(
            reportData, "zx_notes_payable") + getSubject(reportData, "zx_non_cur_liab_due_within_1y") + getSubject(
            reportData, "zx_st_bonds_payable") + getSubject(
            reportData, "zx_lt_borrow") + getSubject(
            reportData, "zx_bonds_payable") + getSubject(
            reportData, "zx_lt_payable_tot") + getSubject(
            reportData, "zx_int_payable")
    except Exception as e:
        print("计算有息债务发生异常", e)
        return None


def getYxzwT0(reportData):
    ret = {
        "dqjk_t0": getSubject(reportData, "zx_st_borrow"),
        "jrfz_t0": getSubject(reportData, "zx_tradable_fin_liab"),
        "yfpj_t0": getSubject(reportData, "zx_notes_payable"),
        "fldfz_t0": getSubject(reportData, "zx_non_cur_liab_due_within_1y"),
        "yfdz_t0": getSubject(reportData, "zx_st_bonds_payable"),
        "yfk_t0": getSubject(reportData, "zx_lt_payable_tot"),
        "yflx_t0": getSubject(reportData, "zx_int_payable"),
        "cqjk_t0": getSubject(reportData, "zx_lt_borrow"),
        "yfzq_t0": getSubject(reportData, "zx_bonds_payable"),
    }
    return ret;


LevelMapping = {
    "T001": {
        "AAA": "L1",
        "AA+": "L2+",
        "AA": "L2",
        "AA-": "L2-",
        "A+": "L3+",
        "A": "L3",
        "A-": "L3-",
        "BBB+": "L4+",
        "BBB": "L4",
        "BBB-": "L4-",
        "BB+": "L5+",
        "BB": "L5",
        "BB-": "L5-",
        "B+": "L6+",
        "B": "L6",
        "B-": "L6-",
        "CCC": "L7",
        "CC": "L8",
        "C": "L9",
    }
}

# 特殊调级
AdjustmentLevel = [
    {
        "creditCode": "91100000102063897J",
        "year": "2021",
        "sector": "综合",
        "level": "L1"
    },
    {
        "creditCode": "91110000100005220B",
        "year": "2021",
        "sector": "综合",
        "level": "L1"
    },
    {
        "creditCode": "91110000710935089N",
        "year": "2021",
        "sector": "综合",
        "level": "L1"
    },
    {
        "creditCode": "9110000010168558XU",
        "year": "2021",
        "sector": "",
        "level": "L1"
    },
]


def levelConvert(level, typeCode, year, creditCode):
    if level is None:
        return None
    try:
        result = list(filter(lambda x: x['creditCode'] == creditCode and x['year'] == year, AdjustmentLevel))
        if len(result) > 0:
            return result[0]['level']
    except Exception as e:
        return level

    try:
        if LevelMapping.__contains__(typeCode) == False:
            return level
        return LevelMapping[typeCode][level]
    except Exception as e:
        print(e)
        return None


def getYxfz(report):
    return getSubject(report, "zx_st_borrow") + getSubject(report, "zx_tradable_fin_liab") + getSubject(report,
                                                                                                        "zx_notes_payable") + getSubject(
        report, "zx_non_cur_liab_due_within_1y") + getSubject(report, "zx_st_bonds_payable") + getSubject(report,
                                                                                                          "zx_lt_borrow") + getSubject(
        report, "zx_bonds_payable") + getSubject(report, "zx_lt_payable_tot") + getSubject(report, "zx_int_payable")


# activity15 预付账款周转率
# debtcoverage10 debtcoverage10 现金及等价物/短期有息债务
# debtcoverage12 经营活动产生的现金流量净额/负债合计
# growth2 归属母公司所有者净利润同比增长率
# leverage3 有息负债率
# profitability16 销售毛利率
def getFindex(reportT0, reportT1):
    ret = {

        "activity15": {
            "sum_value": '',
            "sub_value": {
                "cost_t0": getNumber(reportT0, "zx_oper_cost"),
                "prepay_t0": getNumber(reportT0, "zx_prepay"),
                "prepay_t1": getNumber(reportT1, "zx_prepay")
            },

        },
        "debtcoverage10": {
            "sum_value": '',
            "sub_value": {
                "balance_t0": getNumber(reportT0, "zx_cash_cash_equ_end_period"),
                "debt_t0": getDqyxzw(reportT0)
            }

        },
        "debtcoverage12": {
            "sum_value": '',
            "sub_value": {
                "flow_t0": getNumber(reportT0, "zx_net_cash_flows_oper_act"),
                "debt_t0": getNumber(reportT0, "zx_tot_liab")
            }

        },
        "growth2": {
            "sum_value": '',
            "sub_value": {
                "profit_t0": getNumber(reportT0, "zx_np_belongto_parcomsh"),
                "profit_t1": getNumber(reportT1, "zx_np_belongto_parcomsh")
            }
        },
        "leverage3": {
            "sum_value": '',
            "sub_value": {
                "debt_t0": getYxfz(reportT0),
                "assets_t0": getNumber(reportT0, "zx_tot_assets"),
            }

        },
        "profitability16": {
            "sum_value": '',
            "sub_value": {
                "revenue_t0": getNumber(reportT0, "zx_oper_rev"),
                "cost_t0": getNumber(reportT0, "zx_oper_cost")
            }
        }
    }
    return ret


def getEsHits(result):
    try:
        return result['hits']['hits']
    except Exception as e:
        traceback.print_exc()
        return None


def isCommandParam(argparse, commandParam):
    try:
        for command in argparse[1:]:
            if command.__contains__(commandParam):
                return {"exist": True,
                        "value": command.replace("-", "", 2).replace("=", "", 1).replace(commandParam, "", 2)}
        return {"exist": False}
    except SystemExit as e:
        return {"exist": False}


def existCommandParam(obj, param):
    return param.exist


# 跑批进度计算

def progress_bar(finish_tasks_number, tasks_number):
    """
    进度条

    :param finish_tasks_number: int, 已完成的任务数
    :param tasks_number: int, 总的任务数
    :return:
    """

    percentage = round(finish_tasks_number / tasks_number * 100)
    print("\r进度: {}%: ".format(percentage), "▓" * (percentage // 2), end="")
    sys.stdout.flush()
